﻿using FirstFloor.ModernUI.Presentation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Microsoft.Practices.Unity;
using appCtx = EasyInvoice.ApplicationContext.AppContext;
using System.ComponentModel;
using FirstFloor.ModernUI.Windows.Controls;
using System.Windows;
using System.Diagnostics;

namespace EasyInvoice.WPF.ViewModel
{
    public class InvoiceViewModel : NotifyPropertyChanged, IDataErrorInfo
    {
        private Services.InvoicesService _serviceInvoices;
        private Services.InvoiceDetailsService _serviceInvoiceDetail;

        //for opening up the Add Client window
        private ICommand showSaveCommand;

        public ICommand ShowSaveCommand
        {
            get
            {
                if (showSaveCommand == null)
                {
                    showSaveCommand = new Common.CommandBase(
                        i => this.SaveInvoice(),
                        i => ((UserViewModel)Properties.Settings.Default.AuthenticatedUser) == null ? false:
                            this.Id==0?((UserViewModel)Properties.Settings.Default.AuthenticatedUser).AddInvoices:
                            ((UserViewModel)Properties.Settings.Default.AuthenticatedUser).EditInvoices );
                }
                return showSaveCommand;
            }
        }

        private void SaveInvoice()
        {
            //save invoice
           this._serviceInvoices.Save(this._invoice);

            //get details from db
           var dbDetails = this._serviceInvoiceDetail.GetAllByInvoiceId(this._invoice.Id).ToList();
            //save details

           foreach (InvoiceDetailViewModel detail in _details)
           {
               if (detail.InvoiceId != this._invoice.Id)
                   detail.InvoiceId = this._invoice.Id;
               detail.Save();

               var dbdetail = dbDetails.Find(d => d.Id == detail.Id);
               if (dbdetail != null) dbDetails.Remove(dbdetail);
           }

            //removing the rest of details cos we deleted from list the existing ones
           dbDetails.ForEach(detail => this._serviceInvoiceDetail.Delete(detail));
           //InvoiceListViewModel parent = appCtx.Instance.IoC.Resolve<InvoiceListViewModel>();
           Repository.ResetInvoices();
           //parent.RefreshCommand.Execute(null);
           //parent.PrintCommand.Execute(null);
        }

        private Model.Invoice _invoice {get;set;}

        private ClientViewModel _client = null;
        private ClientViewModel _seller = null;

        private ObservableCollection<InvoiceDetailViewModel> _details = new ObservableCollection<InvoiceDetailViewModel>();

        public InvoiceViewModel():this(new Model.Invoice()){}
        

        public InvoiceViewModel(EasyInvoice.Model.Invoice inv)
        {
            if (inv == null) inv = new Model.Invoice();
            _invoice = inv;
            this._serviceInvoices = appCtx.Instance.IoC.Resolve<Services.InvoicesService>();
            this._serviceInvoiceDetail = appCtx.Instance.IoC.Resolve<Services.InvoiceDetailsService>();
        }

        public string Number
        {
            get
            {
                return this._invoice.Number;
            }
            set
            {
                this._invoice.Number = value;
                this.OnPropertyChanged("Number");
            }
        }

        public DateTime Date
        {
            get
            {
                return this._invoice.Date;
            }
            set
            {
                this._invoice.Date = value;
                this.OnPropertyChanged("Date");
            }
        }

        public int Id
        {
            get
            {
                return this._invoice.Id;
            }
            set
            {
                this._invoice.Id = value;
                this.OnPropertyChanged("Id");
            }
        }

        public ClientViewModel Client 
        {
            get
            {
                if (this._client == null)
                    if (this._invoice.ClientId!=0)
                        this._client = Repository.Clients.First(client => client.Id == this._invoice.ClientId);
                    //this._client = _allClients.First(client => client.Id == this._invoice.ClientId);
                return this._client;
            }
            set
            {
                if (value != null)
                {
                    this._client = value;
                    this._invoice.ClientId = this._client.Id;
                    this.OnPropertyChanged("Client");
                }
            }
        }

        public ClientViewModel Seller
        {
            get
            {
                if (this._seller == null)
                    if (this._invoice.SellerId != 0)
                        this._seller = Repository.Sellers.First(seller => seller.Id == this._invoice.SellerId);
                //this._seller = _allClients.First(client => client.Id == this._invoice.ClientId);
                return this._seller;
            }
            set
            {
                this._seller = value;
                this._invoice.SellerId = this._seller.Id;
                this.OnPropertyChanged("Seller");
            }
        }

        public ObservableCollection<InvoiceDetailViewModel> Details
        {
            get
            {

                if (this._details.Count == 0)
                    this._details = GetDetails();
                foreach (InvoiceDetailViewModel detail in _details)
                    detail.Index = _details.IndexOf(detail)+1;
                return this._details;
            }
            set
            {

                this._details = value;
                this.OnPropertyChanged("Details");
            }
        }

        private ObservableCollection<InvoiceDetailViewModel> GetDetails()
        {
            var returnValue =  new ObservableCollection<InvoiceDetailViewModel>();

            foreach (Model.InvoiceDetail detail in this._serviceInvoiceDetail.GetAllByInvoiceId(this.Id))
            {
                returnValue.Add(new InvoiceDetailViewModel(detail));
            }
            return returnValue;
        }

        public decimal TotalAmount
        { 
            get{
                if (this._details.Count == 0)
                    this._details = GetDetails();
               return  _details.Sum(d => d.Value);
            }
        }

        public void Delete()
        { 
            //delete details
            this._serviceInvoiceDetail.GetAllByInvoiceId(this._invoice.Id).ToList().ForEach(d => this._serviceInvoiceDetail.Delete(d));
            //delete invoice
            this._serviceInvoices.Delete(this._invoice);
        }

        public string Error
        {
            get { return null; }
        }
        public string this[string columnName]
        {
            get
            {
                if (columnName == "Number")
                {
                    return string.IsNullOrEmpty(this.Number) ? "Required value" : null;
                }
                if (columnName == "Date")
                {
                    return string.IsNullOrEmpty(this.Date.ToString()) ? "Required value" : null;
                }
                if (columnName == "Client")
                {
                    return this.Client == null ? "Required value" : null;
                }
                if (columnName == "Seller")
                {
                    return this.Seller == null ? "Required value" : null;
                }
                if (columnName == "Details")
                {
                    return this.Details.Count == 0 ? "Required value" : null;
                }
                return null;
            }
        }

        //for opening up the Add Client window
        private ICommand printCommand;

        public ICommand PrintCommand
        {
            get
            {
                if (printCommand == null)
                {
                    printCommand = new Common.CommandBase(
                        i => this.PrintInvoice(),
                        i => ((UserViewModel)Properties.Settings.Default.AuthenticatedUser) != null ? ((UserViewModel)Properties.Settings.Default.AuthenticatedUser).PrintInvoices : false);
                }
                return printCommand;
            }
        }

        private void PrintInvoice()
        {
            try
            {
                new Common.InvoiceDocument(this, string.Format("{0}\\{1}-{2}.pdf", EasyInvoice.WPF.Properties.Settings.Default.ExportFolderLocation, this.Number, this.Date.ToString("yyyy-MM-dd")));
            }
            catch (Exception ex)
            {
                ModernDialog.ShowMessage(
                string.Format("Invoice Number {0} from {1} failed to save to file {0}-{2}.pdf.", this.Number, this.Date.ToString("MMMM dd, yyyy"), this.Date.ToString("yyyy-MM-dd"))
                , "Invoice Export Error", MessageBoxButton.OK);
                return;
            }
                var result = ModernDialog.ShowMessage(
                string.Format("Invoice Number {0} from {1} is saved to file {0}-{2}.pdf. \nDo  you want to open it?", this.Number, this.Date.ToString("MMMM dd, yyyy"), this.Date.ToString("yyyy-MM-dd"))
                , "Invoice Exported to pdf", MessageBoxButton.YesNo);
            if (result == MessageBoxResult.Yes)
                Process.Start(string.Format("{0}\\{1}-{2}.pdf", EasyInvoice.WPF.Properties.Settings.Default.ExportFolderLocation, this.Number, this.Date.ToString("yyyy-MM-dd")));
        }

    }
}
